#include "FKDataModel.h"

#include <QStack>

#include "FKDataRecord.h"
#include "FKModelRole.h"

#include "FKLogger.h"

int FKModelData::sInit=FKModelData::declareFKMetaType();

int FKModelData::declareFKMetaType(){
    qRegisterMetaTypeStreamOperators<FKModelData>("FKModelData");
    return qRegisterMetaType<FKModelData>();
}

QDataStream& operator<<(QDataStream& stream,const FKModelData &data){
    return stream<<data.role<<data.data<<data.addressRows<<data.addressProps;
}

QDataStream& operator>>(QDataStream& stream, FKModelData &data){
    stream>>data.role;
    stream>>data.data;
    stream>>data.addressRows;
    stream>>data.addressProps;
    if(data.addressRows.size()!=data.addressProps.size()){
        data.addressRows.clear();
        data.addressProps.clear();
        FK_MLOG("Error loading FKModelData")
    }
    return stream;
}

FKDataModel::FKDataModel(QObject *parent):QAbstractItemModel(parent),_initialized(false){
    FK_CBEGIN
    _root=0;
    FK_CEND
}

FKDataModel::~FKDataModel(){
    FK_DBEGIN
    if(_root)delete _root;
    FK_DEND
}

void FKDataModel::initialize(){
    if(!_initialized)initialization();
}

QVariant FKDataModel::data(const QModelIndex &index, int role) const{
    FKDataRecord* record=this->record(index);
    if(record)return record->data(role);
    return QVariant();
}

bool FKDataModel::setData(const QModelIndex &index, const QVariant &value, int role){
    FKDataRecord* record=this->record(index);
    if(record){
        record->setData(role,value);
        notifyDataChange(index,value,role);
        return true;
    }else{
        return false;
    }
}

int FKDataModel::rowCount(const QModelIndex &parent) const{
    FKDataRecord* record=this->record(parent);
    if(record)return record->rowCount();
    return 0;
 }

int FKDataModel::columnCount(const QModelIndex &parent) const{
    FKDataRecord* record=this->record(parent);
    if(record)return record->columnCount();
    return 0;
}

QModelIndex FKDataModel::index(int row, int column, const QModelIndex &parent) const{
    FKDataRecord* p=record(parent);
    if(p){
        FKDataRecord* r=p->subRecord(row,column);
        if(r)return createIndex(row,column,r);
    }
    return QModelIndex();
}

QModelIndex FKDataModel::parent(const QModelIndex &child) const{
    FKDataRecord* r=record(child);
    if(r){
        FKDataRecord* p=r->parent();
        if(p && p!=_root)return createIndex(p->row(),p->prop(),p);
    }
    return QModelIndex();
}

QHash<int,QByteArray> FKDataModel::roleNames() const{
    QHash<int,QByteArray> h;
    h[FKModelRole::objectID]=FKModelRole::fkqObjectID;
    h[FKModelRole::nameRole]=FKModelRole::fkqNameRole;
    h[FKModelRole::roomDescription]=FKModelRole::fkqRoomDescription;
    h[FKModelRole::roomCapacity]=FKModelRole::fkqRoomCapacity;
    h[FKModelRole::roomUsedCapacity]=FKModelRole::fkqRoomUsedCapacity;
    h[FKModelRole::roomType]=FKModelRole::fkqRoomType;
    h[FKModelRole::score]=FKModelRole::fkqScore;
    return h;
}

void FKDataModel::updateData(FKModelData d){
    QModelIndex i=QModelIndex();
    while(!d.addressRows.isEmpty()){
        QModelIndex parent=i;
        i=index(d.addressRows.pop(),d.addressProps.pop(),parent);
    }
    setData(i,d.data,d.role);
}

void FKDataModel::setRootRecord(FKDataRecord *record){
    if(_root && _root!=record)delete _root;
    _root=record;
}

FKDataRecord* FKDataModel::record(const QModelIndex &index) const{
    if(!_root)return 0;
    if(!index.isValid())return _root;
    return static_cast<FKDataRecord*>(index.internalPointer());
}

void FKDataModel::notifyDataChange(const QModelIndex &index, const QVariant &value, const int &role){
    emit dataChanged(index,index/*,QVector<int>(role)*/);
    QModelIndex i=index;
    QStack<int> addressRows, addressProps;
    while (i.isValid()) {
        addressRows.push(i.row());
        addressProps.push(i.column());
        i=i.parent();
    }
    FKModelData modelData(role,value,addressRows,addressProps);
    emit updateDataRequest(modelData);
}

void FKDataModel::initialization(){
    installNewSource(new FKDataRecord(0));
}

void FKDataModel::installNewSource(FKDataRecord *root){
    emit beginResetModel();
    setRootRecord(root);
    emit endResetModel();
}

QVariant FKDataModel::retriveData()const{
    return _root ? _root->toVariant() : QVariant();
}

void FKDataModel::installNewSource(const QVariant &source){
    installNewSource(new FKDataRecord(0,source));
}
